;; load SDL module
(use-modules ((sdl sdl) #:prefix SDL:)
	     ((sdl gfx) #:prefix SDL:))


(define screen-w 640)         ; screen width
(define screen-h 480)         ; screen height

;; initialize video subsystem
(SDL:init 'video)
(SDL:set-video-mode screen-w screen-h 8 'sw-surface)


;; define constants here
(define ball-radius 5)        ; radius of ball
(define paddle-w 4)           ; paddle width
(define paddle-h 50)          ; paddle height
(define p1-x 20)              ; left paddle's goal-facing side
(define p2-x (- screen-w 20)) ; right paddle's goal-facing side
(define screen (SDL:display-format (SDL:make-surface screen-w screen-h)))

;; the mutable variables will be here
(define p1-score      0)
(define p2-score      0)
(define ball-x        0)
(define ball-y        0)
(define ball-vx       0)
(define ball-vy       0)
(define p1-y          0)
(define p2-y          0)
(define p1-vy         0)
(define p2-vy         0)

;; functions for color
(define (rgba r g b a)
  (logior (ash r 24) (logior (ash g 16) (logior (ash b 8) a))))

(define (rgb r g b)
  (rgba r g b #xFF))

;; pick left (-1) or right (1) for initial ball direction
(define (random-horiz-direction)
  (let ((x (random 2)))
    (cond
     ((= x 0) -1)
     ((= x 1)  1))))

;; event handler
(define (handle-event)
  (let ((e (SDL:make-event)))
    (if (SDL:poll-event e)
        (case (SDL:event:type e)
          ((key-down)
           (case (SDL:event:key:keysym:sym e)
             ((escape q)
              (SDL:quit)
              (quit))
	     ((w)
	      (paddle-up! 1))
	     ((s)
	      (paddle-down! 1))))
	  ((key-up)
	   (case (SDL:event:key:keysym:sym e)
	     ((w s)
	      (paddle-stop! 1))))))))

;; increment player's score by one
(define (inc-score! player)
  (cond ((= player 1) (set! p1-score (+ p1-score 1)))
	((= player 2) (set! p2-score (+ p2-score 1))))
  (init-game!))

;; paddle velocity variable
(define (paddle-down! player)
  (cond ((= player 1) (set! p1-vy 2))
	((= player 2) (set! p2-vy 2))))

(define (paddle-up! player)
  (cond ((= player 1) (set! p1-vy -2))
	((= player 2) (set! p2-vy -2))))

(define (paddle-stop! player)
  (cond ((= player 1) (set! p1-vy 0))
	((= player 2) (set! p2-vy 0))))

;; ball and paddle movement function
;; which also does collision detection
(define (update-positions!)
  (cond ((>= (+ ball-x ball-radius) screen-w)
	 ;; ball passes player 2
	 (inc-score! 1))
	((<= (- ball-x ball-radius) 0)
	 ;; ball passes player 1
	 (inc-score! 2))
	(else
	 (cond
	  ((or (> (+ ball-y ball-radius) screen-h)
	       (< (- ball-y ball-radius) 0))
	   ;; bounce ball off of top and bottom walls
	   (set! ball-vy (- ball-vy)))
	  ((or
	    (and (<= (abs (- ball-y p1-y)) (quotient paddle-h 2))
		 (=  (- ball-x ball-radius) (+ p1-x paddle-w)))
	    (and (<= (abs (- ball-y p2-y)) (quotient paddle-h 2))
		 (=  (+ ball-x ball-radius) (- p2-x paddle-w))))
	   (set! ball-vx (- ball-vx))
	   (set! ball-vy (- (random 4) 2))))))
	
  (set! ball-x (+ ball-x ball-vx))
  (set! ball-y (+ ball-y ball-vy))

  ;; automatically move the right paddle
  (cond
   ((< ball-y (- p2-y (quotient paddle-h 2))) (paddle-up! 2))
   ((> ball-y (+ p2-y (quotient paddle-h 2))) (paddle-down! 2))
   (else (paddle-stop! 2)))

  ;; if paddles aren't going off-screen, move them
  (cond
   ((not (or (>= (+ p1-y p1-vy (quotient paddle-h 2)) screen-h)
	     (<= (+ p1-y p1-vy (- (quotient paddle-h 2))) 0)))
    (set! p1-y (+ p1-y p1-vy))))
  (cond
   ((not (or (>= (+ p2-y p2-vy (quotient paddle-h 2)) screen-h)
	     (<= (+ p2-y p2-vy (- (quotient paddle-h 2))) 0)))
    (set! p2-y (+ p2-y p2-vy)))))

;; drawing loop
(define (render)
  (let ((format (SDL:surface-get-format screen)))
    ;; draw background
    (SDL:draw-rectangle screen 0 0 screen-w screen-h (rgb 50 0 100) #t)

    ;; draw ball
    (SDL:draw-circle screen
		     ball-x ball-y ball-radius
		     (rgb 255 255 255) #t)

    ;; draw paddles (from left to right)
    (SDL:draw-rectangle screen
	                p1-x              (- p1-y (quotient paddle-h 2))
			(+ p1-x paddle-w) (+ p1-y (quotient paddle-h 2))
			(rgb 255 255 255) #t)

    (SDL:draw-rectangle screen
	                (- p2-x paddle-w) (- p2-y (quotient paddle-h 2))
			p2-x              (+ p2-y (quotient paddle-h 2))
			(rgb 255 255 255) #t)

    ;; copy surface to screen
    (SDL:blit-surface screen)
    (SDL:flip)
    (SDL:delay 3)))

;; set game to initial state
(define (init-game!)
  (set! ball-x  (quotient screen-w 2))
  (set! ball-y  (quotient screen-h 2))
  (set! ball-vx (random-horiz-direction))
  (set! ball-vy (- (random 5) 2))
  (set! p1-y    (quotient screen-h 2))
  (set! p2-y    (quotient screen-h 2))
  (set! p1-vy   0)
  (set! p2-vy   0)
  (main-loop))

;; main loop
(define (main-loop)
  (handle-event)
  (render)
  (update-positions!)
  (main-loop))

;; start game and loop until user presses 'q' or Escape
(init-game!)
